A data network is generally consisted of a network of nodes connected by point-to-point links. Each physical link may support a number of logical point-to-point channels. Each channel may be a bi-directional communication path for allowing commands and message data to flow between two connect nodes within the data network. Each channel may refer to a single point-to-point connection where message data may be transferred between two endpoints or systems. Data may be transmitted in packets including groups called cells from source to destination often through intermediate nodes.
In many data networks, hardware and software may often be used to support asynchronous data transfers between two memory regions, often on different systems. Each system may correspond to a multi-processor system including one or more processors. Each system may serve as a source (initiator) system which initiates a message data transfer (message send operation) or a target system of a message passing operation (message receive operation). Examples of such a multi-processor system may include host servers providing a variety of applications or services, and I/O units providing storage oriented and network oriented IO services. Requests for work (I/O operations) may be posted to shared resources (such as work queues and other memory elements associated with a given hardware adapter), the requested operation may then be performed. However, it is the responsibility of the system which initiates such a request to insure that a shared resource is in an appropriate state to do the work.
In order to improve the performance capabilities of software drivers on a multi-processor system, multiple threads of operation can concurrently initiate new work (I/O operations) and process completed work (I/O operations) on shared resources. The threads initiating and completing work (I/O operations) check the state of a shared resource before performing any work. Events such as descriptor errors, or a user request can cause a shared resource to change states. Therefore care must be taken when changing the state of a shared resource in order to prevent threads initiating and completing work (I/O operations) from performing work (I/O operations) on the shared resource in an invalid state. Furthermore, any thread wishing to update or change the state of a shared resource must be synchronized with all the threads processing work (I/O operations) in order to maintain state integrity. Moreover, shared resources that may be simultaneously accessed by multiple threads can still be compromised if not protected. Mutual exclusion locks have been used to resolve conflict of concurrent access requests of multiple threads in which any one thread may hold the lock while other threads trying to acquire the same lock may be blocked until the lock is available. However, mutual exclusion locks are not suitable for synchronizing multiple threads with a single thread since such a lock forces strict serialization of all the threads—only a single thread can run at any given time. Therefore, there is a need for a mechanism to synchronize multiple threads of operation with a single thread of control and achieve mutual exclusion between multiple threads processing work (I/O operations) on a shared resource and a single thread updating or changing the state of a shared resource without requiring strict serialization of all threads.